package com.dongdong.android.framework.download;

import android.content.Context;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public class DownloadManager {

    public static String TAG = "DownloadManager";
    public static final long TOTAL_ERROR = -1;
    private HashMap<String, FileInfo> mDownTaskQueue;
    private HashMap<String, DownloadStatusListener> mDownListenerQueue;
    private HashMap<String, DownloadRunnable> mDownRunable;
    public DownloadHandler mMainHandler;
    public static int MaxPoolSize = 5;
    private OkHttpClient okHttpClient;
    private String mAbsolutePath;
    private Context mContext = null;


    private DownloadManager() {
        mDownTaskQueue = new HashMap<>();
        mDownListenerQueue = new HashMap<>();
        mDownRunable = new HashMap<>();
        mMainHandler = new DownloadHandler(mDownListenerQueue);
        okHttpClient = new OkHttpClient();
    }

    private static class DownloadManagerHolder {
        private final static DownloadManager instance = new DownloadManager();
    }

    public static DownloadManager getInstance(Context context) {
        DownloadManager manager = DownloadManagerHolder.instance;
        manager.get(context);
        return manager;
    }


    private void get(Context context) {
        if (mContext == null && context == null) {
            throw new IllegalArgumentException("You cannot start a load on a null Context");
        } else if (mContext == null) {
            this.mContext = context.getApplicationContext();
            mAbsolutePath = mContext.getExternalFilesDir("FileDownload").getAbsolutePath();
        }
    }


    public void download(FileInfo info, DownloadStatusListener listener) {
        if (info == null || TextUtils.isEmpty(info.getUrl())) {
            Log.e(TAG, "The Url can't be empty！");
            return;
        }
        if (listener == null) {
            Log.e(TAG, "The Listener can't be empty！");
            return;
        }
        mDownListenerQueue.put(info.getUrl(), listener);
        if (info.getLength() == TOTAL_ERROR || TextUtils.isEmpty(info.getLocalPath())) {
            onPrepare(info);
        } else {
            doDownload(info);
        }
    }


    public void start(FileInfo info) {
        if (info == null || TextUtils.isEmpty(info.getUrl())) {
            Log.e(TAG, "The Url can't be empty！");
            return;
        }
        doDownload(info);
    }

    public void pause(FileInfo info) {
        if (info == null || TextUtils.isEmpty(info.getUrl())) {
            Log.e(TAG, "The Url can't be empty！");
            return;
        }

        DownloadRunnable downloadRunnable = mDownRunable.get(info.getUrl());
        boolean remove = downloadRunnable.onPause(downloadRunnable.getTaskInThread());
        if (remove) {
            mDownRunable.remove(info.getUrl());
        }
    }

    public boolean cancel(FileInfo info) {
        if (info == null || TextUtils.isEmpty(info.getUrl())) {
            Log.e(TAG, "The Url can't be empty！");
            return false;
        }

        if (mDownTaskQueue.containsKey(info.getUrl())) {
            DownloadRunnable downloadRunnable = mDownRunable.get(info.getUrl());
            boolean remove = downloadRunnable.onPause(downloadRunnable.getTaskInThread());
            mDownTaskQueue.remove(info.getUrl());
            mDownRunable.remove(info.getUrl());
            mDownListenerQueue.remove(info.getUrl());
            deleteFile(info.getLocalPath());
            return true;
        }
        return false;
    }

    private void onPrepare(final FileInfo info) {

        if (TextUtils.isEmpty(info.getLocalPath())) {
            String filePath = mAbsolutePath + "/" + info.getName();
            info.setLocalPath(filePath);
            long filesize = getFileSize(filePath);
            if (filesize > 0) {
                info.setStart(filesize);
            } else {
                Log.e(TAG, "The File creation failed！");
                mDownListenerQueue.get(info.getUrl()).error(info.getUrl(), "The File creation failed");
            }

        }

        if (info.getLength() == TOTAL_ERROR) {
            Request request = new Request.Builder()
                    .get()
                    .url(info.getUrl())
                    .build();
            okHttpClient.newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    Log.e(TAG, "The File parsing error！");
                    mDownListenerQueue.get(info.getUrl()).error(info.getUrl(), "The File parsing error");
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    try {
                        //判断请求是否取消
                        if (call.isCanceled()) {
                            Log.e(TAG, "The File parsing error！");
                            mDownListenerQueue.get(info.getUrl()).error(info.getUrl(), "The File parsing error");
                            return;
                        }

                        if (response != null && response.isSuccessful()) {
                            long contentLength = response.body().contentLength();
                            contentLength = contentLength == 0 ? TOTAL_ERROR : contentLength;
                            if (contentLength != TOTAL_ERROR) {
                                info.setLength(contentLength);
                                doDownload(info);
                            }
                        } else {
                            Log.e(TAG, "The File parsing error！");
                            mDownListenerQueue.get(info.getUrl()).error(info.getUrl(), "The File parsing error");
                            return;
                        }


                    } catch (Exception e) {//发生异常，失败回调
                        Log.e(TAG, "The File parsing error！");
                        mDownListenerQueue.get(info.getUrl()).error(info.getUrl(), "The File parsing error");
                    } finally {//记得关闭操作
                        response.close();
                    }


                }
            });

        } else {
            doDownload(info);
        }


    }

    private void doDownload(FileInfo info) {
        mDownTaskQueue.put(info.getUrl(), info);
        if (info.getStart() == info.getLength()) {
            info.setProgress(100);
            Message msg = new Message();
            msg.what = StatusMode.SUCCESS.getValue();
            msg.obj = info;
            mMainHandler.sendMessage(msg);
            return;
        }
        if (DownloadThreadPool.getInstance().getActiveCount() < MaxPoolSize) {
            DownloadRunnable downrunnable = new DownloadRunnable(info, mMainHandler, okHttpClient);
            DownloadThreadPool.getInstance().execute(downrunnable);
            mDownRunable.put(info.getUrl(), downrunnable);
        } else {
            Log.d(TAG, "The biggest download number no more than five！");
            mDownListenerQueue.get(info.getUrl()).error(info.getUrl(), "The biggest download number no more than five！");
        }

    }


    private long getFileSize(String path) {
        File file = new File(path);
        if (file.exists() && file.isFile()) {
            return file.length();
        } else {
            try {
                file.createNewFile();
                return 0;
            } catch (Exception e) {
                e.printStackTrace();
                return -1;
            }
        }


    }

    private boolean deleteFile(String path) {
        File file = new File(path);
        if (file.exists()) {
            return file.delete();
        }
        return true;
    }

}
